home *** CD-ROM | disk | FTP | other *** search
/ Power Hacker 2003 / Power_Hacker_2003.iso / Exploit and vulnerability / w00w00 / exploits / irckill / patches / ircii-4.4 / hook.c next >
Encoding:
C/C++ Source or Header  |  1998-08-13  |  22.3 KB  |  981 lines

  1. /*
  2.  * hook.c: Does those naughty hook functions. 
  3.  *
  4.  * Written By Michael Sandrof
  5.  *
  6.  * Copyright(c) 1990 
  7.  *
  8.  * See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT 
  9.  */
  10.  
  11. /*
  12.  * april 11, 1998
  13.  * patched do_hook() overflow - nyt
  14. */
  15.  
  16.  
  17. #ifndef lint
  18. static    char    rcsid[] = "@(#)$Id: hook.c,v 1.37 1997/04/21 06:34:00 mrg Exp $";
  19. #endif /* lint */
  20.  
  21. #include "irc.h"
  22.  
  23. #include "hook.h"
  24. #include "vars.h"
  25. #include "ircaux.h"
  26. #include "alias.h"
  27. #include "list.h"
  28. #include "window.h"
  29. #include "server.h"
  30. #include "output.h"
  31. #include "edit.h"
  32.  
  33. #ifdef    INCLUDE_UNUSED_FUNCTIONS
  34. static  void    flush_on_hooks _((void));
  35. #endif /* INCLUDE_UNUSED_FUNCTIONS */
  36. static    char    *fill_it_out _((char *, int));
  37. static    void    setup_struct _((int, int, int, int));
  38. static    int    Add_Remove_Check _((List *, char *));
  39. static    int    Add_Remove_Check_List _((List *, List*));
  40. static    void    add_numeric_hook _((int, char *, char *, int, int, int, int));
  41. static    void    add_hook _((int, char *, char *, int, int, int, int));
  42. static    int    show_numeric_list _((int));
  43. static    int    show_list _((int));
  44. static    void    remove_numeric_hook _((int, char *, int, int, int));
  45. static    void    write_hook _((FILE *, Hook *, char *));
  46.  
  47. #define SILENT 0
  48. #define QUIET 1
  49. #define NORMAL 2
  50. #define NOISY 3
  51.  
  52. /*
  53.  * The various ON levels: SILENT means the DISPLAY will be OFF and it will
  54.  * suppress the default action of the event, QUIET means the display will be
  55.  * OFF but the default action will still take place, NORMAL means you will be
  56.  * notified when an action takes place and the default action still occurs,
  57.  * NOISY means you are notified when an action occur plus you see the action
  58.  * in the display and the default actions still occurs 
  59.  */
  60. static    char    *noise_level[] = { "SILENT", "QUIET", "NORMAL", "NOISY" };
  61.  
  62. #define    HS_NOGENERIC    0x1000
  63. #define    HF_LOOKONLY    0x0001
  64. #define HF_NORECURSE    0x0002
  65. #define HF_GLOBAL    0x0004
  66.  
  67. extern    int    load_depth;
  68.  
  69.     int    in_on_who = 0;
  70.  
  71.     NumericList *numeric_list = (NumericList *) 0;
  72. /* hook_functions: the list of all hook functions available */
  73.     HookFunc FAR hook_functions[] =
  74. {
  75.     { "ACTION",        (Hook *) 0,    3,    0,    0 },
  76.     { "CHANNEL_NICK",    (Hook *) 0,    3,    0,    0 },
  77.     { "CHANNEL_SIGNOFF",    (Hook *) 0,    3,    0,    0 },
  78.     { "CONNECT",        (Hook *) 0,    1,    0,    0 },
  79.     { "CTCP",        (Hook *) 0,    4,    0,    0 },
  80.     { "CTCP_REPLY",        (Hook *) 0,    3,    0,    0 },
  81.     { "DCC_CHAT",        (Hook *) 0,    2,    0,    0 },
  82.         { "DCC_CONNECT",        (Hook *) 0,     2,      0,      0 },
  83.         { "DCC_ERROR",          (Hook *) 0,     6,      0,      0 },
  84.         { "DCC_LOST",           (Hook *) 0,     2,      0,      0 },
  85.     { "DCC_RAW",        (Hook *) 0,    3,    0,    0 },
  86.         { "DCC_REQUEST",        (Hook *) 0,     4,      0,      0 },
  87.     { "DISCONNECT",        (Hook *) 0,    1,    0,    0 },
  88.         { "ENCRYPTED_NOTICE",   (Hook *) 0,     3,      0,      0 },
  89.         { "ENCRYPTED_PRIVMSG",  (Hook *) 0,     3,      0,      0 },
  90.     { "EXEC",        (Hook *) 0,    2,    0,    0 },
  91.     { "EXEC_ERRORS",    (Hook *) 0,    2,    0,    0 },
  92.     { "EXEC_EXIT",        (Hook *) 0,    3,    0,    0 },
  93.     { "EXEC_PROMPT",    (Hook *) 0,    2,    0,    0 },
  94.         { "EXIT",               (Hook *) 0,     1,      0,      0 },
  95.     { "FLOOD",        (Hook *) 0,    3,    0,    0 },
  96.     { "HELP",        (Hook *) 0,    2,    0,    0 },
  97.     { "HOOK",        (Hook *) 0,    1,    0,    0 },
  98.     { "IDLE",        (Hook *) 0,    1,    0,    0 },
  99.     { "INPUT",        (Hook *) 0,    1,    0,    0 },
  100.     { "INVITE",        (Hook *) 0,    2,    0,    0 },
  101.     { "JOIN",        (Hook *) 0,    2,    0,    0 },
  102.     { "KICK",        (Hook *) 0,    3,    0,    HF_LOOKONLY },
  103.     { "LEAVE",        (Hook *) 0,    2,    0,    0 },
  104.     { "LIST",        (Hook *) 0,    3,    0,    HF_LOOKONLY },
  105.     { "MAIL",        (Hook *) 0,    2,    0,    0 },
  106.     { "MODE",        (Hook *) 0,    3,    0,    0 },
  107.     { "MSG",        (Hook *) 0,    2,    0,    0 },
  108.     { "MSG_GROUP",        (Hook *) 0,    3,    0,    0 },
  109.     { "NAMES",        (Hook *) 0,    2,    0,    HF_LOOKONLY },
  110.     { "NICKNAME",        (Hook *) 0,    2,    0,    0 },
  111.     { "NOTE",        (Hook *) 0,    10,    0,    0 },
  112.     { "NOTICE",        (Hook *) 0,    2,    0,    0 },
  113.     { "NOTIFY_SIGNOFF",    (Hook *) 0,    1,    0,    0 },
  114.     { "NOTIFY_SIGNON",    (Hook *) 0,    1,    0,    0 },
  115.     { "PUBLIC",        (Hook *) 0,    3,    0,    0 },
  116.     { "PUBLIC_MSG",        (Hook *) 0,    3,    0,    0 },
  117.     { "PUBLIC_NOTICE",    (Hook *) 0,    3,    0,    0 },
  118.     { "PUBLIC_OTHER",    (Hook *) 0,    3,    0,    0 },
  119.     { "RAW_IRC",        (Hook *) 0,    1,    0,    0 },
  120.     { "SEND_ACTION",    (Hook *) 0,    2,    0,    0 },
  121.     { "SEND_DCC_CHAT",    (Hook *) 0,    2,    0,    0 },
  122.     { "SEND_MSG",        (Hook *) 0,    2,    0,    0 },
  123.     { "SEND_NOTICE",    (Hook *) 0,    2,    0,    0 },
  124.     { "SEND_PUBLIC",    (Hook *) 0,    2,    0,    0 },
  125.     { "SEND_TALK",        (Hook *) 0,    2,    0,    0 },
  126.     { "SERVER_NOTICE",    (Hook *) 0,    1,    0,    0 },
  127.     { "SIGNOFF",        (Hook *) 0,    1,    0,    0 },
  128.     { "TALK",        (Hook *) 0,    2,    0,    0 },
  129.     { "TIMER",        (Hook *) 0,    1,    0,    0 },
  130.     { "TOPIC",        (Hook *) 0,    2,    0,    0 },
  131.     { "WALL",        (Hook *) 0,    2,    0,    HF_LOOKONLY },
  132.     { "WALLOP",        (Hook *) 0,    3,    0,    HF_LOOKONLY },
  133.     { "WHO",        (Hook *) 0,    6,    0,    HF_LOOKONLY },
  134.     { "WIDELIST",        (Hook *) 0,    1,    0,    HF_LOOKONLY },
  135.     { "WINDOW",        (Hook *) 0,    2,    0,    HF_NORECURSE },
  136.     { "WINDOW_KILL",    (Hook *) 0,    1,    0,    0 }
  137. };
  138.  
  139. static char    *
  140. fill_it_out(str, params)
  141.     char    *str;
  142.     int    params;
  143. {
  144.     char    buffer[BIG_BUFFER_SIZE + 1];
  145.     char    *arg,
  146.         *free_ptr = (char *) 0,
  147.         *ptr;
  148.     int    i = 0;
  149.  
  150.     malloc_strcpy(&free_ptr, str);
  151.     ptr = free_ptr;
  152.     *buffer = (char) 0;
  153.     while ((arg = next_arg(ptr, &ptr)) != NULL)
  154.     {
  155.         if (*buffer)
  156.             strmcat(buffer, " ", BIG_BUFFER_SIZE);
  157.         strmcat(buffer, arg, BIG_BUFFER_SIZE);
  158.         if (++i == params)
  159.             break;
  160.     }
  161.     for (; i < params; i++)
  162.         strmcat(buffer, (i < params-1) ? " %" : " *", BIG_BUFFER_SIZE);
  163.     if (*ptr)
  164.     {
  165.         strmcat(buffer, " ", BIG_BUFFER_SIZE);
  166.         strmcat(buffer, ptr, BIG_BUFFER_SIZE);
  167.     }
  168.     malloc_strcpy(&free_ptr, buffer);
  169.     return (free_ptr);
  170. }
  171.  
  172.  
  173. /*
  174.  * A variety of comparison functions used by the hook routines follow.
  175.  */
  176.  
  177. struct    CmpInfoStruc
  178. {
  179.     int    ServerRequired;
  180.     int    SkipSerialNum;
  181.     int    SerialNumber;
  182.     int    Flags;
  183. }    cmp_info;
  184.  
  185. #define    CIF_NOSERNUM    0x0001
  186. #define    CIF_SKIP    0x0002
  187.  
  188. int     cmpinfodone = 0;
  189.  
  190. static void
  191. setup_struct(ServReq, SkipSer, SerNum, flags)
  192.     int    ServReq;
  193.     int    SkipSer;
  194.     int    SerNum;
  195.     int    flags;
  196. {
  197.     cmp_info.ServerRequired = ServReq;
  198.     cmp_info.SkipSerialNum = SkipSer;
  199.     cmp_info.SerialNumber = SerNum;
  200.     cmp_info.Flags = flags;
  201. }
  202.  
  203. static    int
  204. Add_Remove_Check(_Item, Name)
  205.     List    *_Item;
  206.     char    *Name;
  207. {
  208.     int    comp;
  209.     Hook    *Item = (Hook *)_Item;
  210.  
  211.     if (cmp_info.SerialNumber != Item->sernum)
  212.         return (Item->sernum > cmp_info.SerialNumber) ? 1 : -1;
  213.     if ((comp = my_stricmp(Item->nick, Name)) != 0)
  214.             return comp;
  215.     if (Item->server != cmp_info.ServerRequired)
  216.         return (Item->server > cmp_info.ServerRequired) ? 1 : -1;
  217.     return 0;
  218. }
  219.  
  220. static    int
  221. Add_Remove_Check_List(_Item, _Item2)
  222.     List    *_Item;
  223.     List    *_Item2;
  224. {
  225.     return Add_Remove_Check(_Item, _Item->name);
  226. }
  227.  
  228. static    void
  229. add_numeric_hook(numeric, nick, stuff, noisy, not, server, sernum)
  230.     int    numeric;
  231.     char    *nick,
  232.         *stuff;
  233.     int    noisy,
  234.         not;
  235.     int    server,
  236.         sernum;
  237. {
  238.     NumericList *entry;
  239.     Hook    *new;
  240.     char    buf[4];
  241.  
  242.     sprintf(buf, "%3.3u", numeric);
  243.     if ((entry = (NumericList *) find_in_list((List **) &numeric_list, buf, 0)) ==
  244.             (NumericList *) 0)
  245.     {
  246.         entry = (NumericList *) new_malloc(sizeof(NumericList));
  247.         entry->name = (char *) 0;
  248.         entry->list = (Hook *) 0;
  249.         malloc_strcpy(&(entry->name), buf);
  250.         add_to_list((List **) &numeric_list, (List *) entry);
  251.     }
  252.  
  253.     setup_struct((server==-1) ? -1 : (server & ~HS_NOGENERIC), sernum-1, sernum, 0);
  254.     if ((new = (Hook *) remove_from_list_ext((List **) &(entry->list), nick, Add_Remove_Check)) != NULL)
  255.     {
  256.         new->not = 1;
  257.         new_free(&(new->nick));
  258.         new_free(&(new->stuff));
  259.         wait_new_free((char **) &new);
  260.     }
  261.     new = (Hook *) new_malloc(sizeof(Hook));
  262.     new->nick = (char *) 0;
  263.     new->noisy = noisy;
  264.     new->server = server;
  265.     new->sernum = sernum;
  266.     new->not = not;
  267.     new->global = loading_global;
  268.     new->stuff = (char *) 0;
  269.     malloc_strcpy(&new->nick, nick);
  270.     malloc_strcpy(&new->stuff, stuff);
  271.     upper(new->nick);
  272.     add_to_list_ext((List **) &(entry->list), (List *) new, Add_Remove_Check_List);
  273. }
  274.  
  275. /*
  276.  * add_hook: Given an index into the hook_functions array, this adds a new
  277.  * entry to the list as specified by the rest of the parameters.  The new
  278.  * entry is added in alphabetical order (by nick). 
  279.  */
  280. static    void
  281. add_hook(which, nick, stuff, noisy, not, server, sernum)
  282.     int    which;
  283.     char    *nick,
  284.         *stuff;
  285.     int    noisy,
  286.         not;
  287.     int    server,
  288.         sernum;
  289. {
  290.     Hook    *new;
  291.  
  292.     if (which < 0)
  293.     {
  294.         add_numeric_hook(-which, nick, stuff, noisy, not, server,
  295.             sernum);
  296.         return;
  297.     }
  298.     setup_struct((server == -1) ? -1 : (server & ~HS_NOGENERIC), sernum-1, sernum, 0);
  299.     if ((new = (Hook *) remove_from_list_ext((List **) &(hook_functions[which].list), nick, Add_Remove_Check)) != NULL)
  300.     {
  301.         new->not = 1;
  302.         new_free(&(new->nick));
  303.         new_free(&(new->stuff));
  304.         wait_new_free((char **) &new);
  305.     }
  306.     new = (Hook *) new_malloc(sizeof(Hook));
  307.     new->nick = (char *) 0;
  308.     new->noisy = noisy;
  309.     new->server = server;
  310.     new->sernum = sernum;
  311.     new->not = not;
  312.     new->stuff = (char *) 0;
  313.     new->global = loading_global;
  314.     malloc_strcpy(&new->nick, nick);
  315.     malloc_strcpy(&new->stuff, stuff);
  316.     upper(new->nick);
  317.     add_to_list_ext((List **) &(hook_functions[which].list), (List *) new, Add_Remove_Check_List);
  318. }
  319.  
  320. /* show_hook shows a single hook */
  321. extern    void
  322. show_hook(list, name)
  323.     Hook    *list;
  324.     char    *name;
  325. {
  326.     if (list->server != -1)
  327.         say("On %s from \"%s\" do %s [%s] <%d> (Server %d)%s",
  328.             name, list->nick,
  329.             (list->not ? "nothing" : list->stuff),
  330.             noise_level[list->noisy], list->sernum,
  331.             list->server&~HS_NOGENERIC,
  332.             (list->server&HS_NOGENERIC) ? " Exclusive" : empty_string);
  333.     else
  334.         say("On %s from \"%s\" do %s [%s] <%d>",
  335.             name, list->nick,
  336.             (list->not ? "nothing" : list->stuff),
  337.             noise_level[list->noisy],
  338.             list->sernum);
  339. }
  340.  
  341. /*
  342.  * show_numeric_list: If numeric is 0, then all numeric lists are displayed.
  343.  * If numeric is non-zero, then that particular list is displayed.  The total
  344.  * number of entries displayed is returned 
  345.  */
  346. static    int
  347. show_numeric_list(numeric)
  348.     int    numeric;
  349. {
  350.     NumericList *tmp;
  351.     Hook    *list;
  352.     char    buf[4];
  353.     int    cnt = 0;
  354.  
  355.     if (numeric)
  356.     {
  357.         sprintf(buf, "%3.3u", numeric);
  358.         if ((tmp = (NumericList *) find_in_list((List **) &numeric_list, buf, 0))
  359.                 != NULL)
  360.         {
  361.             for (list = tmp->list; list; list = list->next, cnt++)
  362.                 show_hook(list, tmp->name);
  363.         }
  364.     }
  365.     else
  366.     {
  367.         for (tmp = numeric_list; tmp; tmp = tmp->next)
  368.         {
  369.             for (list = tmp->list; list; list = list->next, cnt++)
  370.                 show_hook(list, tmp->name);
  371.         }
  372.     }
  373.     return (cnt);
  374. }
  375.  
  376. /*
  377.  * show_list: Displays the contents of the list specified by the index into
  378.  * the hook_functions array.  This function returns the number of entries in
  379.  * the list displayed 
  380.  */
  381. static    int
  382. show_list(which)
  383.     int    which;
  384. {
  385.     Hook    *list;
  386.     int    cnt = 0;
  387.  
  388.     /* Less garbage when issueing /on without args. (lynx) */
  389.     for (list = hook_functions[which].list; list; list = list->next, cnt++)
  390.         show_hook(list, hook_functions[which].name);
  391.     return (cnt);
  392. }
  393.  
  394. /*
  395.  * do_hook: This is what gets called whenever a MSG, INVITES, WALL, (you get
  396.  * the idea) occurs.  The nick is looked up in the appropriate list. If a
  397.  * match is found, the stuff field from that entry in the list is treated as
  398.  * if it were a command. First it gets expanded as though it were an alias
  399.  * (with the args parameter used as the arguments to the alias).  After it
  400.  * gets expanded, it gets parsed as a command.  This will return as its value
  401.  * the value of the noisy field of the found entry, or -1 if not found. 
  402.  */
  403. /* huh-huh.. this sucks.. im going to re-write it so that it works */
  404. /*VARARGS*/
  405. int
  406. #ifdef HAVE_STDARG_H
  407. do_hook(int which, char *format, ...)
  408. {
  409.     va_list vl;
  410. #else
  411. do_hook(which, format, arg1, arg2, arg3, arg4, arg5, arg6)
  412.     int    which;
  413.     char    *format;
  414.     char    *arg1,
  415.         *arg2,
  416.         *arg3,
  417.         *arg4,
  418.         *arg5,
  419.         *arg6;
  420. {
  421. #endif /* HAVE_STDARG_H */
  422.     Hook    *tmp, **list;
  423.     char    buffer[2*BIG_BUFFER_SIZE + 1],
  424.         *name = (char *) 0;
  425.     int    RetVal = 1;
  426.     unsigned int    display;
  427.     int    i,
  428.         old_in_on_who;
  429.     Hook    *hook_array[2048];
  430.     int    hook_num = 0;
  431.     static    int hook_level = 0;
  432.     int    len;
  433.     char    *foo;
  434.  
  435.     hook_level++;
  436.     bzero(buffer, sizeof(buffer));
  437.  
  438. #ifdef HAVE_STDARG_H
  439.     va_start(vl, format);
  440.     vsprintf(buffer, format, vl);
  441.     va_end(vl);
  442. #else
  443.     sprintf(buffer, format, arg1, arg2, arg3, arg4, arg5, arg6);
  444. #endif /* HAVE_STDARG_H */
  445.     if (which < 0)
  446.     {
  447.         NumericList *hook;
  448.         char    buf[4];
  449.  
  450.         sprintf(buf, "%3.3u", -which);
  451.         if ((hook = (NumericList *) find_in_list((List **) &numeric_list, buf, 0))
  452.                 != NULL)
  453.         {
  454.             name = hook->name;
  455.             list = &hook->list;
  456.         }
  457.         else
  458.             list = (Hook **) 0;
  459.     }
  460.     else
  461.     {
  462.         if (hook_functions[which].mark && (hook_functions[which].flags & HF_NORECURSE))
  463.             list = (Hook **) 0;
  464.         else
  465.         {
  466.             list = &(hook_functions[which].list);
  467.             name = hook_functions[which].name;
  468.         }
  469.     }
  470.     if (!list)
  471.         return really_free(--hook_level), 1;
  472.  
  473.     if (which >= 0)
  474.         hook_functions[which].mark++;
  475.             /* not attached, so dont "fix" it */
  476.     {
  477.         int currser = 0, oldser = 0;
  478.         int currmatch = 0, oldmatch = 0;
  479.         Hook *bestmatch = (Hook *) 0;
  480.         int nomorethisserial = 0;
  481.  
  482.         for (tmp = *list;tmp;tmp = tmp->next)
  483.         {
  484.             currser = tmp->sernum;
  485.             if (currser != oldser)      /* new serial number */
  486.             {
  487.                             oldser = currser;
  488.                 currmatch = oldmatch = nomorethisserial = 0;
  489.                 if (bestmatch)
  490.                     hook_array[hook_num++] = bestmatch;
  491.                 bestmatch = (Hook *) 0;
  492.             }
  493.  
  494.             if (nomorethisserial) 
  495.                 continue;
  496.                     /* if there is a specific server
  497.                        hook and it doesnt match, then
  498.                        we make sure nothing from
  499.                        this serial number gets hooked */
  500.             if ((tmp->server != -1) &&
  501.                (tmp->server & HS_NOGENERIC) &&
  502.                (tmp->server != (from_server & HS_NOGENERIC)))
  503.             {
  504.                 nomorethisserial = 1;
  505.                 bestmatch = (Hook *) 0;
  506.                 continue;
  507.             }
  508.             currmatch = wild_match(tmp->nick,buffer);
  509.             if (currmatch > oldmatch)
  510.             {
  511.                 oldmatch = currmatch;
  512.                 bestmatch = tmp;
  513.             }
  514.         }
  515.         if (bestmatch)
  516.             hook_array[hook_num++] = bestmatch;
  517.     }
  518.  
  519.     for (i = 0; i < hook_num; i++)
  520.     {
  521.         tmp = hook_array[i];
  522.         if (!tmp)
  523.         {
  524.             if (which >= 0)
  525.                 hook_functions[which].mark--;
  526.             return really_free(--hook_level), RetVal;
  527.         }
  528.         if (tmp->not)
  529.             continue;
  530.         send_text_flag = which;
  531.         if (tmp->noisy > QUIET)
  532.             say("%s activated by \"%s\"", name, buffer);
  533.         display = window_display;
  534.         if (tmp->noisy < NOISY)
  535.             window_display = 0;
  536.  
  537.         save_message_from();
  538.         old_in_on_who = in_on_who;
  539.         if (which == WHO_LIST || (which <= -311 && which >= -318))
  540.             in_on_who = 1;
  541.         len = strlen(tmp->stuff) + 1; 
  542.         foo = new_malloc(len);
  543.         bcopy(tmp->stuff, foo, len);
  544.         parse_line((char *) 0, foo, buffer, 0, 0);
  545.         new_free(&foo);
  546.         in_on_who = old_in_on_who;
  547.         window_display = display;
  548.         send_text_flag = -1;
  549.         restore_message_from();
  550.         if (!tmp->noisy && !tmp->sernum)
  551.             RetVal = 0;
  552.     }
  553.     if (which >= 0)
  554.         hook_functions[which].mark--;
  555.     return really_free(--hook_level), RetVal;
  556. }
  557.  
  558. static    void
  559. remove_numeric_hook(numeric, nick, server, sernum, quiet)
  560.     int    numeric;
  561.     char    *nick;
  562.     int    server;
  563.     int    sernum;
  564.     int    quiet;
  565. {
  566.     NumericList *hook;
  567.     Hook    *tmp,
  568.         *next;
  569.     char    buf[4];
  570.  
  571.     sprintf(buf, "%3.3u", numeric);
  572.     if ((hook = (NumericList *) find_in_list((List **) &numeric_list, buf,0)) != NULL)
  573.     {
  574.         if (nick)
  575.         {
  576.             setup_struct((server == -1) ? -1 :
  577.                 (server & ~HS_NOGENERIC), sernum - 1, sernum, 0);
  578.             if ((tmp = (Hook *) remove_from_list((List **) &(hook->list), nick)) != NULL)
  579.             {
  580.                 if (!quiet)
  581.                     say("\"%s\" removed from %s list", nick, buf);
  582.                 tmp->not = 1;
  583.                 new_free(&(tmp->nick));
  584.                 new_free(&(tmp->stuff));
  585.                 wait_new_free((char **) &tmp);
  586.                 if (hook->list == (Hook *) 0)
  587.                 {
  588.                     if ((hook = (NumericList *) remove_from_list((List **) &numeric_list, buf)) != NULL)
  589.                     {
  590.                         new_free(&(hook->name));
  591.                         new_free(&hook);
  592.                     }
  593.                 }
  594.                 return;
  595.             }
  596.         }
  597.         else
  598.         {
  599.             for (tmp = hook->list; tmp; tmp = next)
  600.             {
  601.                 next = tmp->next;
  602.                 tmp->not = 1;
  603.                 new_free(&(tmp->nick));
  604.                 new_free(&(tmp->stuff));
  605.                 wait_new_free((char **) &tmp);
  606.             }
  607.             hook->list = (Hook *) 0;
  608.             if (!quiet)
  609.                 say("The %s list is empty", buf);
  610.             return;
  611.         }
  612.     }
  613.     if (quiet)
  614.         return;
  615.     if (nick)
  616.         say("\"%s\" is not on the %s list", nick, buf);
  617.     else
  618.         say("The %s list is empty", buf);
  619. }
  620.  
  621. #ifdef    INCLUDE_UNUSED_FUNCTIONS
  622. static  void   
  623. flush_on_hooks()
  624. {
  625.         int    x;
  626.         int    old_display = window_display;
  627.         
  628.         window_display = 0;
  629.         for (x = 100 ; x < 999; x++)
  630.                 remove_numeric_hook(x, (char *) 0, 1, x, 0);
  631.         for (x = 0 ; x < NUMBER_OF_LISTS; x++)
  632.                 remove_hook(x, (char *) 0, 1, x, 0);
  633.         window_display = old_display;
  634. }
  635. #endif /* INCLUDE_UNUSED_FUNCTIONS */
  636.  
  637. extern    void
  638. remove_hook(which, nick, server, sernum, quiet)
  639.     int    which;
  640.     char    *nick;
  641.     int    server,
  642.         sernum,
  643.         quiet;
  644. {
  645.     Hook    *tmp,
  646.         *next;
  647.  
  648.     if (which < 0)
  649.     {
  650.         remove_numeric_hook(-which, nick, server, sernum, quiet);
  651.         return;
  652.     }
  653.     if (nick)
  654.     {
  655.         setup_struct((server == -1) ? -1 : (server & ~HS_NOGENERIC),
  656.             sernum-1, sernum, 0);
  657.         if ((tmp = (Hook *) remove_from_list_ext((List **) &hook_functions[which].list, nick, Add_Remove_Check)) != NULL)
  658.         {
  659.             if (!quiet)
  660.                 say("\"%s\" removed from %s list", nick, hook_functions[which].name);
  661.             tmp->not = 1;
  662.             new_free(&(tmp->nick));
  663.             new_free(&(tmp->stuff));
  664.             wait_new_free((char **) &tmp);
  665.         }
  666.         else if (!quiet)
  667.             say("\"%s\" is not on the %s list", nick, hook_functions[which].name);
  668.     }
  669.     else
  670.     {
  671.         for(tmp = hook_functions[which].list; tmp; tmp=next)
  672.         {
  673.             next = tmp->next;
  674.             tmp->not = 1;
  675.             new_free(&(tmp->nick));
  676.             new_free(&(tmp->stuff));
  677.             wait_new_free((char **) &tmp);
  678.         }
  679.         hook_functions[which].list = (Hook *) 0;
  680.         if (!quiet)
  681.             say("The %s list is empty", hook_functions[which].name);
  682.     }
  683. }
  684.  
  685. /* on: The ON command */
  686. /*ARGSUSED*/
  687. void
  688. on(command, args, subargs)
  689.     char    *command,
  690.         *args,
  691.         *subargs;
  692. {
  693.     char    *func,
  694.         *nick,
  695.         *serial,
  696.         *cmd = (char *) 0;
  697.     /* int noisy = NORMAL, not = 0, remove = 0, -not used */
  698.     int    noisy,
  699.         not,
  700.         server,
  701.         sernum,
  702.         remove,
  703.         len,
  704.         which = 0,
  705.         cnt,
  706.         i;
  707.  
  708.     if (get_int_var(NOVICE_VAR) && !load_depth)
  709.     {
  710.         yell("*** You may not type ON commands when you have the NOVICE");
  711.         yell("*** variable set to ON. Some ON commands may cause a");
  712.         yell("*** security breach on your machine, or enable another");
  713.         yell("*** user to control your IRC session. Read the help files");
  714.         yell("*** in /HELP ON before using ON");
  715.         return;
  716.     }
  717.     if ((func = next_arg(args, &args)) != NULL)
  718.     {
  719.         if (*func == '#')
  720.         {
  721.             if (!(serial = next_arg(args, &args)))
  722.             {
  723.                 say("No serial number specified");
  724.                 return;
  725.             }
  726.             sernum = atoi(serial);
  727.             func++;
  728.         }
  729.         else
  730.             sernum = 0;
  731.         switch (*func)
  732.         {
  733.         case '&':
  734.             server = from_server;
  735.             func++;
  736.             break;
  737.         case '@':
  738.             server = from_server|HS_NOGENERIC;
  739.             func++;
  740.             break;
  741.         default:
  742.             server = -1;
  743.             break;
  744.         }
  745.         switch (*func)
  746.         {
  747.         case '-':
  748.             noisy = QUIET;
  749.             func++;
  750.             break;
  751.         case '^':
  752.             noisy = SILENT;
  753.             func++;
  754.             break;
  755.         case '+':
  756.             noisy = NOISY;
  757.             func++;
  758.             break;
  759.         default:
  760.             noisy = NORMAL;
  761.             break;
  762.         }
  763.         if ((len = strlen(func)) == 0)
  764.         {
  765.             say("You must specify an event type!");
  766.             return;
  767.         }
  768.         malloc_strcpy(&cmd, func);
  769.         upper(cmd);
  770.         for (cnt = 0, i = 0; i < NUMBER_OF_LISTS; i++)
  771.         {
  772.             if (!strncmp(cmd, hook_functions[i].name, len))
  773.             {
  774.                 if (strlen(hook_functions[i].name) == len)
  775.                 {
  776.                     cnt = 1;
  777.                     which = i;
  778.                     break;
  779.                 }
  780.                 else
  781.                 {
  782.                     cnt++;
  783.                     which = i;
  784.                 }
  785.             }
  786.             else if (cnt)
  787.                 break;
  788.         }
  789.         if (cnt == 0)
  790.         {
  791.             if (is_number(cmd))
  792.             {
  793.                 which = atoi(cmd);
  794.                 if ((which < 0) || (which > 999))
  795.                 {
  796.                     say("Numerics must be between 001 and 999");
  797.                     goto out;
  798.                 }
  799.                 which = -which;
  800.             }
  801.             else
  802.             {
  803.                 say("No such ON function: %s", func);
  804.                 goto out;
  805.             }
  806.         }
  807.         else if (cnt > 1)
  808.         {
  809.             say("Ambiguous ON function: %s", func);
  810.             goto out;
  811.         }
  812.         else 
  813.         {
  814.             if (get_int_var(INPUT_PROTECTION_VAR) && !my_strnicmp(hook_functions[which].name, "INPUT", 5))
  815.             {
  816.                 say("You cannot use /ON INPUT with INPUT_PROTECTION set");
  817.                 say("Please read /HELP ON INPUT, and /HELP SET INPUT_PROTECTION");
  818.                 goto out;
  819.             }
  820.         }
  821.         remove = 0;
  822.         not = 0;
  823.         switch (*args)
  824.         {
  825.         case '-':
  826.             remove = 1;
  827.             args++;
  828.             break;
  829.         case '^':
  830.             not = 1;
  831.             args++;
  832.             break;
  833.         }
  834.         if ((nick = new_next_arg(args, &args)) != NULL)
  835.         {
  836.             if (which < 0)
  837.                 nick = fill_it_out(nick, 1);
  838.             else
  839.                 nick = fill_it_out(nick,
  840.                     hook_functions[which].params);
  841.             if (remove)
  842.             {
  843.                 if (strlen(nick) == 0)
  844.                     say("No expression specified");
  845.                 else
  846.                     remove_hook(which, nick, server,
  847.                         sernum, 0);
  848.             }
  849.             else
  850.             {
  851.                 if (not)
  852.                     args = empty_string;
  853.                 if (*nick)
  854.                 {
  855.                     if (*args == LEFT_BRACE)
  856.                     {
  857.                         char    *ptr = MatchingBracket(++args,
  858.                                 LEFT_BRACE, RIGHT_BRACE);
  859.                         if (!ptr)
  860.                         {
  861.                             say("Unmatched brace in ON");
  862.                             new_free(&nick);
  863.                             goto out;
  864.                         }
  865.                         else if (ptr[1])
  866.                         {
  867.                             say("Junk after closing brace in ON");
  868.                             new_free(&nick);
  869.                             goto out;
  870.                         }
  871.                         else
  872.                             *ptr = '\0';
  873.                     }
  874.                     add_hook(which, nick, args, noisy, not, server, sernum);
  875.                     if (which < 0)
  876.                         say("On %3.3u from \"%s\" do %s [%s] <%d>",
  877.                             -which, nick, (not ? "nothing" : args),
  878.                             noise_level[noisy], sernum);
  879.                     else
  880.                         say("On %s from \"%s\" do %s [%s] <%d>",
  881.                             hook_functions[which].name, nick,
  882.                             (not ? "nothing" : args),
  883.                             noise_level[noisy], sernum);
  884.                 }
  885.             }
  886.             new_free(&nick);
  887.         }
  888.         else
  889.         {
  890.             if (remove)
  891.                 remove_hook(which, (char *) 0, server,
  892.                     sernum, 0);
  893.             else
  894.             {
  895.                 if (which < 0)
  896.                 {
  897.                     if (show_numeric_list(-which) == 0)
  898.                         say("The %3.3u list is empty.",
  899.                             -which);
  900.                 }
  901.                 else if (show_list(which) == 0)
  902.                     say("The %s list is empty.",
  903.                         hook_functions[which].name);
  904.             }
  905.         }
  906.     }
  907.     else
  908.     {
  909.         int    total = 0;
  910.  
  911.         say("ON listings:");
  912.         for (which = 0; which < NUMBER_OF_LISTS; which++)
  913.             total += show_list(which);
  914.         total += show_numeric_list(0);
  915.         if (total == 0)
  916.             say("All ON lists are empty.");
  917.     }
  918. out:
  919.     new_free(&cmd);
  920. }
  921.  
  922. static    void
  923. write_hook(fp, hook, name)
  924.     FILE    *fp;
  925.     Hook    *hook;
  926.     char    *name;
  927. {
  928.     char    *stuff = (char *) 0;
  929.  
  930.     if (hook->server!=-1)
  931.         return;
  932.     switch (hook->noisy)
  933.     {
  934.     case SILENT:
  935.         stuff = "^";
  936.         break;
  937.     case QUIET:
  938.         stuff = "-";
  939.         break;
  940.     case NORMAL:
  941.         stuff = empty_string;
  942.         break;
  943.     case NOISY:
  944.         stuff = "+";
  945.         break;
  946.     }
  947.     if (hook->sernum)
  948.         fprintf(fp, "ON #%s%s %d \"%s\"", stuff, name, hook->sernum,
  949.             hook->nick);
  950.     else
  951.         fprintf(fp, "ON %s%s \"%s\"", stuff, name, hook->nick);
  952.     fprintf(fp, " %s\n", hook->stuff);
  953. }
  954.  
  955. /*
  956.  * save_hooks: for use by the SAVE command to write the hooks to a file so it
  957.  * can be interpreted by the LOAD command 
  958.  */
  959. void
  960. save_hooks(fp, do_all)
  961.     FILE    *fp;
  962.     int    do_all;
  963. {
  964.     Hook    *list;
  965.     NumericList *numeric;
  966.     int    which;
  967.  
  968.     for (which = 0; which < NUMBER_OF_LISTS; which++)
  969.     {
  970.         for (list = hook_functions[which].list; list; list = list->next)
  971.             if (!list->global || do_all)
  972.                 write_hook(fp,list, hook_functions[which].name);
  973.     }
  974.     for (numeric = numeric_list; numeric; numeric = numeric->next)
  975.     {
  976.         for (list = numeric->list; list; list = list->next)
  977.             if (!list->global)
  978.                 write_hook(fp, list, numeric->name);
  979.     }
  980. }
  981.